/*
 * Copyright (C) 2015 Daniel Uppenkamp
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.googlecode.maurersmarbles;

import com.google.common.base.Preconditions;

/**
 *
 * @author Daniel Uppenkamp
 */
public class Rectangle {

    /**
     * The height of the rectangle.
     */
    protected int height;
    /**
     * The width of the rectangle.
     */
    protected int width;
    /**
     * The x coordinate of the upper left corner of the rectangle.
     */
    protected int x;
    /**
     * The y coordinate of the upper left corner of the rectangle.
     */
    protected int y;

    /**
     * Creates a new Rectangle with an upper left corner at (0,0) and a width
     * and height of 0.
     */
    public Rectangle() {
        // do nothing
    }

    /**
     * Creates a new Rectangle from the coordinates of the given rectangle.
     *
     * @param rectangle the rectangle to copy from
     */
    public Rectangle(Rectangle rectangle) {

        Preconditions.checkNotNull(rectangle, "Null rectangle");

        x = rectangle.x;
        y = rectangle.y;
        width = rectangle.width;
        height = rectangle.height;

    }

    /**
     * Creates a new Rectangle from the given inputs.
     *
     * @param x the x coordinate of the upper left corner
     * @param y the y coordinate of the upper left corner
     * @param width the width of the rectangle
     * @param height the height of the rectangle
     */
    public Rectangle(int x, int y, int width, int height) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }

    /**
     * Creates a new Rectangle with the given width and height and the upper
     * left corner at (0,0).
     *
     * @param width the width of the rectangle
     * @param height the height of the rectangle
     */
    public Rectangle(int width, int height) {
        this.width = width;
        this.height = height;
    }

    /**
     * Returns whether or not the rectangle contains the given x, y coordinate.
     *
     * @param x the x coordinate of the point to test
     * @param y the y coordinate of the point to test
     * @return whether or not the rectangle contains the given x, y coordinate
     */
    public boolean contains(int x, int y) {
        return inside(x, y);
    }

    /**
     * Returns the y coordinate of the lower right corner.
     *
     * @return the y coordinate of the lower right corner
     */
    public int getBottom() {
        return y + height;
    }

    /**
     * Returns the center x coordinate of the rectangle.
     *
     * @return the center x coordinate of the rectangle
     */
    public int getCenterX() {
        return x + (width / 2);
    }

    /**
     * Returns the center y coordinate of the rectangle.
     *
     * @return the center y coordinate of the rectangle
     */
    public int getCenterY() {
        return y + (height / 2);
    }

    /**
     * Returns the height of the rectangle.
     *
     * @return the height of the rectangle
     */
    public int getHeight() {
        return height;
    }

    /**
     * Returns the x coordinate of the upper left corner.
     *
     * @return the x coordinate of the upper left corner
     */
    public int getLeft() {
        return x;
    }

    /**
     * Returns the lower left point of the rectangle.
     *
     * @return the lower left point of the rectangle
     */
    public Point getLowerLeftPoint() {
        return new Point(x, y + height);
    }

    /**
     * Returns the lower right point of the rectangle.
     *
     * @return the lower right point of the rectangle
     */
    public Point getLowerRightPoint() {
        return new Point(x + width, y + height);
    }

    /**
     * Returns the x coordinate of the lower right corner.
     *
     * @return the x coordinate of the lower right corner
     */
    public int getRight() {
        return x + width;
    }

    /**
     * Returns the y coordinate of the upper left corner.
     *
     * @return the y coordinate of the upper left corner
     */
    public int getTop() {
        return y;
    }

    /**
     * Returns the upper left point of the rectangle.
     *
     * @return the upper left point of the rectangle
     */
    public Point getUpperLeftPoint() {
        return new Point(x, y);
    }

    /**
     * Returns the upper right point of the rectangle.
     *
     * @return the upper right point of the rectangle
     */
    public Point getUpperRightPoint() {
        return new Point(x + width, y);
    }

    /**
     * Returns the width of the rectangle.
     *
     * @return the width of the rectangle
     */
    public int getWidth() {
        return width;
    }

    /**
     * Returns the x coordinate of the upper left corner.
     *
     * @return the x coordinate of the upper left corner
     */
    public int getX() {
        return x;
    }

    /**
     * Returns the y coordinate of the upper left corner.
     *
     * @return the y coordinate of the upper left corner
     */
    public int getY() {
        return y;
    }

    /**
     * Returns whether or not the given x, y coordinate is inside the rectangle.
     *
     * @param x the x coordinate of the point to test
     * @param y the y coordinate of the point to test
     * @return whether or not the given x, y coordinate is inside the rectangle
     */
    public boolean inside(int x, int y) {
        return width > 0 && height > 0
                && x >= this.x && x < this.x + width
                && y >= this.y && y < this.y + height;
    }

    /**
     * Returns a rectangle that is linearly interpolated between rectangle1 and
     * rectangle2 by the given weight.
     *
     * @param rectangle1 the first rectangle
     * @param rectangle2 the second rectangle
     * @param weight the weight between rectangle1 and rectangle2 (0.0 - 1.0)
     * @return a rectangle that is linearly interpolated between rectangle1 and
     * rectangle2 by the given weight
     */
    public static Rectangle interpolate(Rectangle rectangle1, Rectangle rectangle2, double weight) {

        Preconditions.checkNotNull(rectangle1, "Null rectangle1");
        Preconditions.checkNotNull(rectangle2, "Null rectangle2");

        Point upperLeftPoint = Point.interpolate(rectangle1.getUpperLeftPoint(), rectangle2.getUpperLeftPoint(), weight);
        Point lowerRightPoint = Point.interpolate(rectangle1.getLowerRightPoint(), rectangle2.getLowerRightPoint(), weight);

        int startX = upperLeftPoint.getX();
        int startY = upperLeftPoint.getY();
        int width = lowerRightPoint.getX() - upperLeftPoint.getX();
        int height = lowerRightPoint.getY() - upperLeftPoint.getY();

        return new Rectangle(startX, startY, width, height);

    }

}
